<?php
/**
* A simple database connector
* @todo sqlite connector
* @todo postgresql connector
* @todo switch to mysqli for mysql
* @link http://webappkit.net
* @package webappkit
* @subpackage db
* @author J.Ducastel <nospam0@ducastel.name>
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
*/
class DbLinkTool extends WakTool {

    /**
     * active dblink tool, usually last created
     */
    public static $active;

    protected $cfg=array(
        'dblink'=>array(
            'host' => 'localhost'
            ,'db' => null
            ,'user' => 'root'
            , 'pwd' => null
            ,'encoding'=>null));

    //protected $link;

    /**
     * @var object mysqli instance
     */
    protected $mysqli;

    /**
     * @var string current database
     */
    protected $db;

    /**
     * @var bool true if connection is active
     */
    protected $connected;

    /**
     * tool factory
     * registers last created DbLinkTool as global $DBLINKTOOL
     */
    public static function toolFactory($kit_id, $cfg=array()) {
        if (!class_exists('mysqli')) {
            throw new Exception("DbLink needs mysqli while running PHP5", E_USER_WARNING);
        }
        $tool = new DblinkTool($kit_id,$cfg);
        $tool->setActive();
        return $tool;
    }

    /**
     * get active link
     * @return DbLinkTool
     */
    public static function & getActive() {
        return self::$active;
    }

    /**
     * registers itself as current active
     */
    public function setActive() {
        self::$active = &$this;
        return true;
    }

    /**
     * tells if is itself the active link
     * @return bool
     */
    public function isActive() {
        return self::$active == $this;
    }

    /**
     * connects to database using configuration data
     * @access public
     * @return bool
     */
    public function connect() {
        // trying to connect user to host
        $host=$this->cfg['dblink']['host'];
        $user=$this->cfg['dblink']['user'];
        $pwd=$this->cfg['dblink']['pwd'];
        if (!$this->mysqli = new MySQLi($host,$user,$pwd)) {
            throw new Exception("could not connect user $user to host $host");
            return false;
        }
        $this->connected = true;
        // selecting db
        $db = $this->cfg['dblink']['db'];
        if ($db and !$this->selectDb($db)) {
            // throw new Exception("could not select db $db");
            // print_r($this);
            return false;
        }
        // setting encoding
        if (isset($this->cfg['dblink']['encoding'])
        and $encoding=$this->cfg['dblink']['encoding']
        and !$this->setEncoding($encoding)) {
            throw new Exception("could not set encoding $encoding");
            // print_r($this);
            return false;
        }
        return true;
    }

    /**
     * selects database
     * @param string $db databse name
     * @return bool
     */
    public function selectDb($db) {
        if (!$this->connected) {
            throw new Exception("could not select DB $db, link not established");
            return false;
        }
        if (!$this->mysqli->select_db($db))
            return false;
        $this->db = $db; // echo "<h1>$db >> {$this->db}</h1>";
        return true;
    }

    /**
     * tells the current database
     * @return string
     */
    public function getDb() {
        return $this->db;
    }

    /**
    * executes a sql query
    *
    * for SELECT, SHOW, DESCRIBE or EXPLAIN, will return a DbResult
    * @access public
    * @param string $sql sql query
    * @return bool|DbResult
    * /
    public function query($sql) {
        $this->_requireConnection();
        $result = $this->mysqli->query($sql); // print_r($result);
        if (is_bool($result))
            return $result;
        return DbResult::fromResult($result, $sql);
    }/**/

    /**
     * gets a DbResult from SQL query
     * @param string $sql SQL query
     * @return DbResult
     */
    public function getResult($sql) {
        $this->_requireConnection();
        return new DbResult($sql, $this->mysqli);
    }/**/

    /**
     * get results for a list of queries
     * @param array $queries list of sql strings
     * @param bool $transactional if true, use transactional mechanism
     * @return array list of DbResult objects
     */
    public function getResults($queries, $transactional=false) {
        $this->_requireConnection();
        if ($transactional)
            $this->mysqli->autocommit(false);
        $results = array();
        foreach ($queries as $sql) {
            $result = $this->getResult($sql);
            if (!$result->execute()) { // a query failed !!!
                if ($transactional) {
                    // rolling back transaction
                    $this->mysqli->rollback();
                }
                break;
            }
        }
        // commit transaction, then back to autocommit
        if ($transactional) {
            $this->mysqli->commit();
            $this->mysqli->autocommit(true);
        }
        return $results;
    }/**/

    /**
     * execute an insert / update / delete query
     * @param string $sql SQL query
     * @return bool
     */
    public function executeSql($sql) {
        $this->_requireConnection();
        return $this->mysqli->query($sql);
    }/**/

    /**
     * get last insert id
     * @return string
     */
    public function insertId() {
        return $this->mysqli->insert_id;
    }

    /**
     * executes multiple queries
     *
     * @access public
     * @param string $sql
     * @return bool true if all queries succeeded
     */
    function multiQuery($sql) {
        $this->_requireConnection();
        if (!$this->mysqli->multi_query($sql))
            return false;
        if ($this->mysqli->more_results()) {
            do {
                $result = $this->mysqli->use_result();
                if (is_a($result, 'mysqli_result'))
                    $result->close();
                // echo "Okay\n";
            } while ($this->mysqli->next_result());
        }
        return $this->mysqli->errno?false:true;
    }

    /**
     * sets connexion encoding
     * @param string $encoding
     * @return bool
     */
    public function setEncoding($encoding) {
        $this->_requireConnection();
        return $this->mysqli->set_charset($encoding);
    }

    /**
     * gets connexion encoding
     * @return string
     */
    public function getEncoding() {
        $this->_requireConnection();
        $char = $this->mysqli->get_charset();
        // we get a data object
        return $char->charset;
    }

    /**
     *
     */
    public function getError() {
        return $this->mysqli->error;
    }

    /**
     * gets mysqli instance reference
     * @return mysqli
     */
    public function & getMysqli() {
        return $this->mysqli;
    }

    /**
     * make sure a connection is established or throws an exception
     * @return bool
     */
    protected function _requireConnection() {
        if (!$this->connected)
            $this->connect();
        // selecting db
        /*if ($this->db and !$this->selectDb($this->cfg['dblink']['db'])) {
            throw new Exception("could not select DB {$this->cfg['dblink']['db']}");
            return false;
        }*/
        return true;
    }
}
